//
// Copyright (c) 2011 Alex Nesterenko
//

#include "nane/RenderSystem/ogl/OGLWin32WindowContext.h"
#include "nane/RenderSystem/ogl/OGLAPI.h"
#include "nane/core/log.h"
#include "nane/core/ISubSystem.h"

namespace nane
{
    ////////////////////////////////////////////////////////////////////////////////////////////////
    template<>
    void createSubSystem<OGLWindowContext>( OGLWindowContext** _system )
    {
        *_system = new OGLWin32WindowContext();
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////
    template<>
    void releaseSubSystem<OGLWindowContext>( OGLWindowContext* _system )
    {
        delete static_cast<OGLWin32WindowContext*>(_system);
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////
    OGLWin32WindowContext::OGLWin32WindowContext()
        : m_windowHandle( NULL )
        , m_hdc( NULL )
        , m_hglrc( NULL )
        , m_pWglCreateContext( NULL )
        , m_pWglMakeCurrent( NULL )
        , m_pWglDeleteContext( NULL )
        , m_hOpenGL( NULL )
    {

    }
    ////////////////////////////////////////////////////////////////////////////////////////////////
    OGLWin32WindowContext::~OGLWin32WindowContext()
    {

    }
    ////////////////////////////////////////////////////////////////////////////////////////////////
    bool OGLWin32WindowContext::initialize( IWindow::OSHandle _windowHandle )
    {
        if( _window == NULL )
        {
            LOG_ERROR("Window handle must be valid");
            return false;
        }
        m_windowHandle = _windowHandle;
        HWND hWnd = reinterpret_cast<HWND>(m_windowHandle);
        m_hdc = ::GetDC(hWnd);
        if( m_hdc == NULL )
        {
            LOG_ERROR("Failed to get window HDC");
            return false;
        }

        m_hOpenGL = DynamicModule::loadModule("opengl32.dll");
        if( m_hOpenGL == NULL )
        {
            LOG_ERROR("Failed to load OGL API");
            return false;
        }
        m_pWglCreateContext = reinterpret_cast<PFUNCWGLCREATECONTEXT>(DynamicModule::getFunction(m_hOpenGL, "wglCreateContext"));
        m_pWglMakeCurrent = reinterpret_cast<PFUNCWGLMAKECURRENT>(DynamicModule::getFunction(m_hOpenGL, "wglMakeCurrent"));
        m_pWglDeleteContext = reinterpret_cast<PFUNCWGLDELETECONTEXT>(DynamicModule::getFunction(m_hOpenGL, "wglDeleteContext"));
        if( m_pWglCreateContext == NULL || m_pWglMakeCurrent == NULL || m_pWglDeleteContext == NULL )
        {
            LOG_ERROR("Failed to get wgl functions");
            DynamicModule::unloadModule(m_hOpenGL);
            return false;
        }

        PIXELFORMATDESCRIPTOR pfd;
        memset(&pfd, 0, sizeof(pfd));
        pfd.nSize = sizeof(pfd);
        pfd.nVersion = 1;
        pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
        pfd.iPixelType = PFD_TYPE_RGBA;
        pfd.cColorBits = 24;                    // fixme
        pfd.cAlphaBits = 8;                     // fixme
        pfd.cDepthBits = 16;                    // fixme
        pfd.cStencilBits = 0;                   // fixme

        int format = 0;
        format = ChoosePixelFormat(m_hdc, &pfd);
        if( format == 0 )
        {
            LOG_ERROR( "Failed to choose pixel format" );
            return false;
        }
        BOOL res = SetPixelFormat(m_hdc, format, &pfd);
        if( res == FALSE )
        {
            LOG_ERROR( "Failed to set pixel format" );
            return false;
        }
        m_hglrc = m_pWglCreateContext(m_hdc);
        if( m_hglrc == 0 )
        {
            LOG_ERROR( "Failed to create OpenGL context" );
            return false;
        }
        if( m_pWglMakeCurrent(m_hdc, m_hglrc) != TRUE )
        {
            LOG_ERROR( "Failed to make current OpenGL context" );
            return false;
        }

        //wglSwapIntervalEXT = (PFNWGLSWAPINTERVALFARPROC)wglGetProcAddress( "wglSwapIntervalEXT" );
        return InitializeOpenGLAPI("opengl32.dll");
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////
    void OGLWin32WindowContext::shutdown()
    {
        if( m_hglrc != NULL )
        {
            m_pWglDeleteContext(m_hglrc);
        }
        ReleaseOpenGLAPI();
        DynamicModule::unloadModule(m_hOpenGL);
        m_hOpenGL = NULL;
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////
    void OGLWin32WindowContext::swapBuffers()
    {
        SwapBuffers(m_hdc);
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////
}
